/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.*;
import java.security.spec.*;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.swing.JOptionPane;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 *
 * @author Tuan
 */
public class EmailTools {
    
    
    public static  void GeneratorKey(Key privateKey, Key publicKey)
    {
        try {
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
            kpg.initialize(1024);
            KeyPair kp = kpg.genKeyPair();
            publicKey = kp.getPublic();
            privateKey = kp.getPrivate();            
            
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(null, ex.toString());
        }
    }
    
    public static  String EncrypByKey(String fullPath_Key,String strSource, Integer keyType)
    {
        /**
         * keyType = 0: use Public Key
         * keyType = 1: use Private Key
         */
        String obResult = "";
        try {            
            
            File fileKey = new File(fullPath_Key);
            FileInputStream fis = new FileInputStream(fullPath_Key);
            byte[] encodedKey = new byte[(int) fileKey.length()];
            fis.read(encodedKey);
            fis.close();
            
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);
            Cipher enCipher = Cipher.getInstance("RSA");
            if(keyType == 0)
            {
                PublicKey publicKey = keyFactory.generatePublic(keySpec);
                enCipher.init(Cipher.ENCRYPT_MODE, publicKey);
            }
            else
            {
                PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
                enCipher.init(Cipher.ENCRYPT_MODE, privateKey);
            }
            
            byte[] byteData = strSource.getBytes();
            byte[] byteResult= enCipher.doFinal(byteData);
            obResult =  new BASE64Encoder().encode(byteResult);
            
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(null, ex.toString());
        }
        return obResult;
    }
    
    public static  String DecrypByKey(String fullPath_Key,String strSource, Integer keyType)
    {
        /**
         * keyType = 0: use Public Key
         * keyType = 1: use Private Key
         */
        String obResult = "";
        try {            
            
            File fileKey = new File(fullPath_Key);
            FileInputStream fis = new FileInputStream(fullPath_Key);
            byte[] encodedKey = new byte[(int) fileKey.length()];
            fis.read(encodedKey);
            fis.close();
            
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            Cipher enCipher = Cipher.getInstance("RSA");
            if(keyType == 0)
            {
                X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey);
                PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
                enCipher.init(Cipher.DECRYPT_MODE, publicKey);
            }
            else
            {
                PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedKey);
                PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
                enCipher.init(Cipher.DECRYPT_MODE, privateKey);
            }
            
            byte[] decordedValue = new BASE64Decoder().decodeBuffer(strSource);
            byte[] byteResult = enCipher.doFinal(decordedValue);
            
            
            obResult = new String(byteResult);
            
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(null, ex.toString());
        }
        return obResult;
    }
    
    
    
    public static KeyPair LoadKeyPair(String path, String algorithm)
            throws IOException, NoSuchAlgorithmException,
            InvalidKeySpecException {
        // Read Public Key.
        File filePublicKey = new File(path + "/public.key");
        FileInputStream fis = new FileInputStream(path + "/public.key");
        byte[] encodedPublicKey = new byte[(int) filePublicKey.length()];
        fis.read(encodedPublicKey);
        fis.close();

        // Read Private Key.
        File filePrivateKey = new File(path + "/private.key");
        fis = new FileInputStream(path + "/private.key");
        byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()];
        fis.read(encodedPrivateKey);
        fis.close();

        // Generate KeyPair.
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(
                encodedPublicKey);
        PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

        PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(
                encodedPrivateKey);
        PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

        return new KeyPair(publicKey, privateKey);
    }
    
        
    public static void EncryptOrDecryptFile(String srcFileName, String destFileName,String fullPathKeyFile, int cipherMode) throws Exception {
        /**
         * scryptMode = 0: Enscrypt Data
         * scryptMode = 1: Descrypt Data
         */
        OutputStream outputWriter = null;
        InputStream inputReader = null;
        
        try {
            FileInputStream fis = new FileInputStream(fullPathKeyFile);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            Cipher cipher = Cipher.getInstance("RSA");
            PublicKey publicKey = null;
            PrivateKey privateKey = null;
            if(cipherMode == Cipher.ENCRYPT_MODE)
            {
                //Key Public
                File filePublicKey = new File(fullPathKeyFile);
                byte[] encodedPublicKey = new byte[(int) filePublicKey.length()];
                fis.read(encodedPublicKey);
                fis.close();
                 // Generate KeyPair.
                X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(
                    encodedPublicKey);
                publicKey = keyFactory.generatePublic(publicKeySpec);
                
                cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            }
            else
            {
                //Key private
                File filePrivateKey = new File(fullPathKeyFile);
                byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()];
                fis.read(encodedPrivateKey);
                fis.close();
                 // Generate KeyPair.
                PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(
                encodedPrivateKey);
                privateKey = keyFactory.generatePrivate(privateKeySpec);
                
                cipher.init(Cipher.DECRYPT_MODE, privateKey);
            }
                    
            
            
            String textLine = null;
            byte[] buf = cipherMode == Cipher.ENCRYPT_MODE ? new byte[100] : new byte[128];
            int bufl;
// init the Cipher object for Encryption...
            
// start FileIO
            outputWriter = new FileOutputStream(destFileName);
            inputReader = new FileInputStream(srcFileName);
            while ((bufl = inputReader.read(buf)) != -1) {
                
                byte[] encText = null;
                if (cipherMode == Cipher.ENCRYPT_MODE) {
                    encText = encrypt(copyBytes(buf, bufl), publicKey);
                } else {
                    encText = decrypt(copyBytes(buf, bufl), privateKey);
                }
                
                outputWriter.write(encText);
            }
            outputWriter.flush();
        } catch (Exception e) {
            throw e;
        } finally {
            try {
                if (outputWriter != null) {
                    outputWriter.close();
                }
                if (inputReader != null) {
                    inputReader.close();
                }
            } catch (Exception e) {
            }
        }
        //JOptionPane.showMessageDialog(null, destFileName);
    }
    
    public static byte[] copyBytes(byte[] arr, int length) {
        byte[] newArr = null;
        if (arr.length == length) {
            newArr = arr;
        } else {
            newArr = new byte[length];
            for (int i = 0; i < length; i++) {
                newArr[i] = (byte) arr[i];
            }
        }
        
        return newArr;
    }
    
     public static byte[] encrypt(byte[] text, PublicKey key) throws Exception {
        byte[] cipherText = null;
        try {
// get an RSA cipher object and print the provider
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
// encrypt the plaintext using the public key
            cipher.init(Cipher.ENCRYPT_MODE, key);
            cipherText = cipher.doFinal(text);
        } catch (Exception e) {
            throw e;
        }
        return cipherText;
    }

    public static byte[] decrypt(byte[] text, PrivateKey key) throws Exception {
        byte[] dectyptedText = null;
        try {
// decrypt the text using the private key
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.DECRYPT_MODE, key);
            try {
                dectyptedText = cipher.doFinal(text);
            } catch (Exception e) {
                
                e.printStackTrace();
            }
        } catch (Exception e) {
            throw e;
        }
        return dectyptedText;
    }
    
    
    public static byte[] CreateSignature(String fullPathPrivateKey,String strContent) throws Exception
    {
        byte[] byteSignedData = null;
        try
        {
            File fileKey = new File(fullPathPrivateKey);
            FileInputStream fis = new FileInputStream(fullPathPrivateKey);
            byte[] encodedKey = new byte[(int) fileKey.length()];
            fis.read(encodedKey);
            fis.close();

            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedKey);
            PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

            Signature mySign = Signature.getInstance("MD5withRSA");
            mySign.initSign(privateKey);
            mySign.update(strContent.getBytes());
            byteSignedData = mySign.sign();
        }
        catch(Exception ex)
        {
            throw ex;
        }
        return byteSignedData;
    }
    
    public static boolean VerifySignature(String fullPathPublicKey,byte [] byteSignedData,String strContent )throws Exception
    {
        boolean status = false;
        try {
            
            File fileKey = new File(fullPathPublicKey);
            FileInputStream fis = new FileInputStream(fullPathPublicKey);
            byte[] encodedKey = new byte[(int) fileKey.length()];
            fis.read(encodedKey);
            fis.close();

            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey);
            PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

            Signature mySign = Signature.getInstance("MD5withRSA");
            mySign.initVerify(publicKey);
            mySign.update(strContent.getBytes());
            status = mySign.verify(byteSignedData);
        }
        catch (Exception e) {
            throw e;
        }
        return status;
    }
    
    //PreShare Key
    public static byte[] EncryptByPreSharedKey(byte[] arrData, String fullPathKeyFile ) throws Exception {
        File fileKey = new File(fullPathKeyFile);
        FileInputStream fis = new FileInputStream(fullPathKeyFile);
        byte[] encodedKey = new byte[(int) fileKey.length()];
        fis.read(encodedKey);
        fis.close();
        
        Key key = new SecretKeySpec(encodedKey, "AES");    
        Cipher c = Cipher.getInstance("AES");
        c.init(Cipher.ENCRYPT_MODE, key);
        byte[] encVal = c.doFinal(arrData);
        //String encryptedValue = new BASE64Encoder().encode(encVal);
        //return encryptedValue;
        return encVal;
    }

    public static String DecryptByPreSharedKey(byte[] arrData, String fullPathKeyFile) throws Exception {
        String result = "";
        try
        {
        
        File fileKey = new File(fullPathKeyFile);
        FileInputStream fis = new FileInputStream(fullPathKeyFile);
        byte[] encodedKey = new byte[(int) fileKey.length()];
        fis.read(encodedKey);
        fis.close();
        
        Key key = new SecretKeySpec(encodedKey, "AES");    
        Cipher c = Cipher.getInstance("AES");
        c.init(Cipher.DECRYPT_MODE, key);
        //byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
        byte[] decValue = c.doFinal(arrData);
        //String decryptedValue = new String(decValue);
        //return decryptedValue;
        //result = new sun.misc.BASE64Encoder().encode(decValue);
        result = new String(decValue);
        }
        catch (Exception e) {
            throw e;
        }
        return result;
    }
    
    
     public static byte[] DecryptByPreSharedKeyForFile(byte[] arrData, String fullPathKeyFile) throws Exception {
        byte[] result;
        try
        {
        
        File fileKey = new File(fullPathKeyFile);
        FileInputStream fis = new FileInputStream(fullPathKeyFile);
        byte[] encodedKey = new byte[(int) fileKey.length()];
        fis.read(encodedKey);
        fis.close();
        
        Key key = new SecretKeySpec(encodedKey, "AES");    
        Cipher c = Cipher.getInstance("AES");
        c.init(Cipher.DECRYPT_MODE, key);
        //byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
        byte[] decValue = c.doFinal(arrData);
        //String decryptedValue = new String(decValue);
        //return decryptedValue;
        //result = new sun.misc.BASE64Encoder().encode(decValue);
        result = decValue;
        }
        catch (Exception e) {
            throw e;
        }
        return result;
    }
}
    
